c7347a84a79728ff27c63489fdb19be7ac06c3de
[openafs.git] / src / ptserver / ptclient.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  *
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12 #include <afs/stds.h>
13
14 #include <roken.h>
15 #include <afs/opr.h>
16
17 #ifdef AFS_NT40_ENV
18 #include <WINNT/afsevent.h>
19 #endif
20
21 #include <rx/xdr.h>
22 #include <rx/rx.h>
23 #include <afs/com_err.h>
24 #include <afs/cellconfig.h>
25 #include <afs/afsutil.h>
26
27 #include "ptclient.h"
28 #include "ptuser.h"
29 #include "pterror.h"
30 #include "display.h"
31
32 afs_int32 security = 0;
33 char confdir[AFSDIR_PATH_MAX];
34
35 char *whoami;
36
37 extern struct ubik_client *pruclient;
38 static void skip(char **);
39 static void PrintHelp(void);
40
41 static int ignoreExist = 0;
42 static char line[256];
43 static char *lineProgress;
44
45 #define WHITESPACE " \t\n"
46
47 int
48 osi_audit(void)
49 {
50 /* OK, this REALLY sucks bigtime, but I can't tell who is calling
51  * afsconf_CheckAuth easily, and only *SERVERS* should be calling osi_audit
52  * anyway.  It's gonna give somebody fits to debug, I know, I know.
53  */
54     return 0;
55 }
56
57 int
58 GetToken(char *format, afs_int32 *l)
59 {
60     int c;
61
62     *l = 0;
63     if (lineProgress == 0)
64         lineProgress = line;
65     c = sscanf(lineProgress, format, l);
66     if (c != 1)
67         return -1;
68     /* skip the white space */
69     lineProgress += strspn(lineProgress, WHITESPACE);
70     /* skip to end of token */
71     lineProgress = strpbrk(lineProgress, WHITESPACE);
72     return 0;
73 }
74
75 #define GetInt32(l) GetToken ("%d", l)
76 #define GetXInt32(l) GetToken ("%x", l)
77
78 int
79 GetString(char *s, int slen)
80 {
81     char *beg;
82     int l;
83     int code;
84
85     if (lineProgress == 0)
86         lineProgress = line;
87     /* skip the white space */
88     lineProgress += strspn(lineProgress, WHITESPACE);
89
90     /* check for quoted string and find end */
91     beg = lineProgress;
92     if (*beg == '"') {
93         l = strcspn(++beg, "\"");
94         if (l == strlen(beg))
95             return -1;          /* unbalanced quotes */
96         lineProgress = beg + l + 1;
97     } else {
98         l = strcspn(beg, WHITESPACE);
99         lineProgress += l;
100     }
101     if (l >= slen) {            /* don't return too much */
102         code = -1;
103         l = slen - 1;
104     } else
105         code = 0;
106
107     strncpy(s, beg, l);
108     s[l] = 0;                   /* null termination */
109     return code;
110 }
111
112 int
113 CodeOk(afs_int32 code)
114 {
115     if (!ignoreExist)
116         return code;
117     return code && (code != PREXIST) && (code != PRIDEXIST);
118 }
119
120 int
121 PrintEntry(afs_int32 ea, struct prentry *e, int indent)
122 {
123     /* handle screwed up versions of DumpEntry */
124     if (e->flags & PRCONT) {
125         afs_int32 id;
126
127         memcpy(&id, e->name, sizeof(id));
128         if ((id != PRBADID) && ((id > (1 << 24)) || (id < -(1 << 24)))) {
129             /* assume server incorrectly swapped these bytes... */
130             int i = 0;
131             while (i < sizeof(e->name)) {
132                 char temp;
133                 temp = e->name[i];
134                 e->name[i] = e->name[i + 3];
135                 e->name[i + 3] = temp;
136                 temp = e->name[i + 1];
137                 e->name[i + 1] = e->name[i + 2];
138                 e->name[i + 2] = temp;
139                 i += 4;
140             }
141         }
142     }
143     return pr_PrintEntry(stdout, /*host order */ 1, ea, e, indent);
144 }
145
146
147 /* main program */
148
149 #include "AFS_component_version_number.c"
150
151 int
152 main(int argc, char **argv)
153 {
154     afs_int32 code;
155     char op[8];
156     char name[PR_MAXNAMELEN];
157     afs_int32 id, oid = ANONYMOUSID, gid;
158     afs_int32 pos;
159     unsigned int i;
160     int n;
161     struct prentry entry;
162     prlist alist;
163     idlist lid;
164     namelist lnames;
165     struct hostent *hostinfo;
166     struct in_addr *hostaddr;
167     afs_int32 *ptr;
168     char *foo;
169     afs_int32 over;
170     char *cell;
171
172 #ifdef  AFS_AIX32_ENV
173     /*
174      * The following signal action for AIX is necessary so that in case of a
175      * crash (i.e. core is generated) we can include the user's data section
176      * in the core dump. Unfortunately, by default, only a partial core is
177      * generated which, in many cases, isn't too useful.
178      */
179     struct sigaction nsa;
180
181     sigemptyset(&nsa.sa_mask);
182     nsa.sa_handler = SIG_DFL;
183     nsa.sa_flags = SA_FULLDUMP;
184     sigaction(SIGSEGV, &nsa, NULL);
185 #endif
186     whoami = argv[0];
187
188     initialize_PT_error_table();
189
190     strcpy(confdir, AFSDIR_CLIENT_ETC_DIRPATH);
191     cell = 0;
192     n = 1;
193     while (n < argc) {
194         int arglen = strlen(argv[n]);
195         char arg[256];
196         lcstring(arg, argv[n], sizeof(arg));
197 #define IsArg(a) (strncmp (arg,a, arglen) == 0)
198         if (IsArg("-testconfdir"))
199             strncpy(confdir, argv[++n], sizeof(confdir));
200         else if (IsArg("client"))
201             strncpy(confdir, AFSDIR_CLIENT_ETC_DIRPATH, sizeof(confdir));
202         else if (IsArg("server"))
203             strncpy(confdir, AFSDIR_SERVER_ETC_DIRPATH, sizeof(confdir));
204         else if (IsArg("0") || IsArg("1") || IsArg("2"))
205             security = atoi(argv[n]);
206         else if (IsArg("-ignoreexist"))
207             ignoreExist++;
208         else if (IsArg("-cell"))
209             cell = argv[++n];
210         else {
211             printf
212                 ("Usage is: 'prclient [-testconfdir <dir> | server | client] [0 | 1 | 2] [-ignoreExist] [-cell <cellname>]\n");
213             exit(1);
214         }
215         n++;
216     }
217
218     printf("Using CellServDB file in %s\n", confdir);
219     if (security == 0)
220         printf("Making unauthenticated connection to prserver\n");
221
222     code = pr_Initialize(security, confdir, cell);
223     if (code) {
224         afs_com_err(whoami, code, "Couldn't initialize protection library");
225         exit(1);
226     }
227
228     while (1) {
229         char *s;
230
231         printf("pr> ");
232         s = fgets(line, sizeof(line), stdin);
233         if (s == NULL)
234             break;
235         lineProgress = 0;
236
237         code = GetString(op, sizeof(op));
238         if (code) {
239             afs_com_err(whoami, PRBADARG,
240                     "error reading opcode in line '%s', got '%.*s'", line,
241                     (int) sizeof(op), op);
242             exit(1);
243         }
244         if (strlen(op) == 0)
245             continue;           /* no input */
246
247         if (!strcmp(op, "cr")) {
248             if (GetString(name, sizeof(name)) || GetInt32(&id)
249                 || GetInt32(&oid))
250                 code = PRBADARG;
251             /* use ubik_Call to do the work, finding an up server and handling
252              * the job of finding a sync site, if need be */
253             else
254                 code = ubik_PR_INewEntry(pruclient, 0, name, id, oid);
255             if (CodeOk(code))
256                 afs_com_err(whoami, code, "on %s %s %d %d", op, name, id, oid);
257         } else if (!strcmp(op, "sf")) {
258             afs_int32 mask, access, gq, uq;
259             if (GetInt32(&id) || GetXInt32(&mask) || GetXInt32(&access)
260                 || GetInt32(&gq) || GetInt32(&uq))
261                 code = PRBADARG;
262             else
263                 code =
264                     ubik_PR_SetFieldsEntry(pruclient, 0, id, mask,
265                               access, gq, uq, 0, 0);
266             if (CodeOk(code))
267                 afs_com_err(whoami, code, "on %s %d %x %x %d %d", op, id, mask,
268                         access, gq, uq);
269         } else if (!strcmp(op, "ce")) {
270             char newname[PR_MAXNAMELEN];
271             afs_int32 newid;
272             if (GetInt32(&id) || GetString(newname, sizeof(newname))
273                 || GetInt32(&oid) || GetInt32(&newid))
274                 code = PRBADARG;
275             else
276                 code =
277                     ubik_PR_ChangeEntry(pruclient, 0, id, newname, oid,
278                               newid);
279             if (CodeOk(code))
280                 afs_com_err(whoami, code, "on %s %d %s %d %d", op, id, newname,
281                         oid, newid);
282         } else if (!strcmp(op, "wh")) {
283             /* scanf("%d",&id); */
284             if (GetInt32(&id))
285                 code = PRBADARG;
286             else
287                 code = ubik_PR_WhereIsIt(pruclient, 0, id, &pos);
288             if (CodeOk(code))
289                 printf("%s\n", pr_ErrorMsg(code));
290             else
291                 printf("location %d\n", pos);
292         } else if (!strcmp(op, "du")) {
293             memset(&entry, 0, sizeof(entry));
294             /* scanf("%d",&pos); */
295             if (GetInt32(&pos))
296                 code = PRBADARG;
297             else
298                 code = ubik_PR_DumpEntry(pruclient, 0, pos, (struct prdebugentry *)&entry);
299             if (CodeOk(code))
300                 printf("%s\n", pr_ErrorMsg(code));
301             if (code == PRSUCCESS) {
302                 PrintEntry(pos, &entry, /*indent */ 0);
303 #if 0
304                 printf("The contents of the entry for %d are:\n", entry.id);
305                 printf("flags %d next %d\n", entry.flags, entry.next);
306                 printf("Groups (or members) \n");
307                 for (i = 0; i < PRSIZE; i++)
308                     printf("%d\n", entry.entries[i]);
309                 printf("nextID %d nextname %d name %s\n", entry.nextID,
310                        entry.nextName, entry.name);
311                 printf("owner %d creator %d\n", entry.owner, entry.creator);
312 #endif
313             }
314         } else if (!strcmp(op, "add") || !strcmp(op, "au")) {
315             /* scanf("%d %d",&id,&gid); */
316             if (GetInt32(&id) || GetInt32(&gid))
317                 code = PRBADARG;
318             else
319                 code = ubik_PR_AddToGroup(pruclient, 0, id, gid);
320             if (CodeOk(code))
321                 afs_com_err(whoami, code, "on %s %d %d", op, id, gid);
322         } else if (!strcmp(op, "iton")) {
323             lid.idlist_val = malloc(20 * sizeof(afs_int32));
324             ptr = lid.idlist_val;
325             lid.idlist_len = 0;
326             foo = line;
327             skip(&foo);
328             while ((lid.idlist_len < 20) && (sscanf(foo, "%d", ptr) != EOF)) {
329                 lid.idlist_len++;
330                 skip(&foo);
331                 ptr++;
332             }
333             if (*foo) {
334                 fprintf(stderr, "too many values specified; max is %d\n", 20);
335             }
336             lnames.namelist_val = 0;
337             lnames.namelist_len = 0;
338             code = ubik_PR_IDToName(pruclient, 0, &lid, &lnames);
339             if (CodeOk(code))
340                 printf("%s\n", pr_ErrorMsg(code));
341             if (code == PRSUCCESS) {
342                 for (i = 0; i < lnames.namelist_len; i++) {
343                     printf("id %d name %s\n", lid.idlist_val[i],
344                            lnames.namelist_val[i]);
345                 }
346                 free(lnames.namelist_val);
347             }
348             free(lid.idlist_val);
349             lid.idlist_val = 0;
350             lid.idlist_len = 0;
351         } else if (!strcmp(op, "ntoi")) {
352             lnames.namelist_val = malloc(PR_MAXLIST * PR_MAXNAMELEN);
353             lnames.namelist_len = 0;
354             foo = line;
355             skip(&foo);
356             for (i = 0; ((lnames.namelist_len < PR_MAXLIST)
357                          && (sscanf(foo, "%63s", lnames.namelist_val[i]) !=
358                              EOF)); i++) {
359                 lnames.namelist_len++;
360                 skip(&foo);
361             }
362             if (*foo) {
363                 fprintf(stderr, "too many values specified; max is %d\n",
364                         PR_MAXLIST);
365             }
366             lid.idlist_val = 0;
367             lid.idlist_len = 0;
368             code = ubik_PR_NameToID(pruclient, 0, &lnames, &lid);
369             if (CodeOk(code))
370                 printf("%s\n", pr_ErrorMsg(code));
371             if (code == PRSUCCESS) {
372                 for (i = 0; i < lid.idlist_len; i++)
373                     printf("name %s id %d\n", lnames.namelist_val[i],
374                            lid.idlist_val[i]);
375                 free(lid.idlist_val);
376             }
377             free(lnames.namelist_val);
378             lnames.namelist_val = 0;
379             lnames.namelist_len = 0;
380         } else if (!strcmp(op, "del")) {
381             /* scanf("%d",&id); */
382             if (GetInt32(&id))
383                 code = PRBADARG;
384             else
385                 code = ubik_PR_Delete(pruclient, 0, id);
386             if (CodeOk(code))
387                 printf("%s\n", pr_ErrorMsg(code));
388         } else if (!strcmp(op, "dg")) {
389             /* scanf("%d",&id); */
390             if (GetInt32(&id))
391                 code = PRBADARG;
392             else
393                 code = ubik_PR_Delete(pruclient, 0, id);
394             if (CodeOk(code))
395                 printf("%s\n", pr_ErrorMsg(code));
396         } else if (!strcmp(op, "rm")) {
397             /* scanf("%d %d",&id,&gid); */
398             if (GetInt32(&id) || GetInt32(&gid))
399                 code = PRBADARG;
400             else
401                 code = ubik_PR_RemoveFromGroup(pruclient, 0, id, gid);
402             if (CodeOk(code))
403                 printf("%s\n", pr_ErrorMsg(code));
404         }
405 #if defined(SUPERGROUPS)
406         else if (!strcmp(op, "lsg")) {
407             alist.prlist_len = 0;
408             alist.prlist_val = 0;
409             /* scanf("%d",&id); */
410             if (GetInt32(&id))
411                 code = PRBADARG;
412             else
413                 code =
414                     ubik_PR_ListSuperGroups(pruclient, 0, id, &alist,
415                               &over);
416             if (CodeOk(code))
417                 printf("%s\n", pr_ErrorMsg(code));
418             if (code == PRSUCCESS) {
419                 ptr = alist.prlist_val;
420                 if (over) {
421                     printf("Number of groups greater than PR_MAXGROUPS!\n");
422                     printf("Excess of %d.\n", over);
423                 }
424                 for (i = 0; i < alist.prlist_len; i++, ptr++)
425                     printf("%d\n", *ptr);
426                 free(alist.prlist_val);
427                 alist.prlist_len = 0;
428                 alist.prlist_val = 0;
429             }
430         }
431 #endif /* SUPERGROUPS */
432         else if (!strcmp(op, "l")) {
433             alist.prlist_len = 0;
434             alist.prlist_val = 0;
435             /* scanf("%d",&id); */
436             if (GetInt32(&id))
437                 code = PRBADARG;
438             else
439                 code = ubik_PR_GetCPS(pruclient, 0, id, &alist, &over);
440             if (CodeOk(code))
441                 printf("%s\n", pr_ErrorMsg(code));
442             if (code == PRSUCCESS) {
443                 ptr = alist.prlist_val;
444                 if (over) {
445                     printf("Number of groups greater than PR_MAXGROUPS!\n");
446                     printf("Excess of %d.\n", over);
447                 }
448                 for (i = 0; i < alist.prlist_len; i++, ptr++)
449                     printf("%d\n", *ptr);
450                 free(alist.prlist_val);
451                 alist.prlist_len = 0;
452                 alist.prlist_val = 0;
453             }
454         } else if (!strcmp(op, "lh")) {
455             alist.prlist_len = 0;
456             alist.prlist_val = 0;
457             /* scanf("%d",&id); */
458             if (GetString(name, sizeof(name)))
459                 code = PRBADARG;
460             else if (!(hostinfo = gethostbyname(name)))
461                 code = PRBADARG;
462             else {
463                 hostaddr = (struct in_addr *)hostinfo->h_addr_list[0];
464                 id = ntohl(hostaddr->s_addr);
465                 code =
466                     ubik_PR_GetHostCPS(pruclient, 0, id, &alist, &over);
467             }
468             if (CodeOk(code))
469                 printf("%s\n", pr_ErrorMsg(code));
470             if (code == PRSUCCESS) {
471                 ptr = alist.prlist_val;
472                 if (over) {
473                     printf("Number of groups greater than PR_MAXGROUPS!\n");
474                     printf("Excess of %d.\n", over);
475                 }
476                 for (i = 0; i < alist.prlist_len; i++, ptr++)
477                     printf("%d\n", *ptr);
478                 free(alist.prlist_val);
479                 alist.prlist_len = 0;
480                 alist.prlist_val = 0;
481             }
482         }
483 #if defined(SUPERGROUPS)
484         else if (!strcmp(op, "m")) {
485             alist.prlist_len = 0;
486             alist.prlist_val = 0;
487             /* scanf("%d",&id); */
488             if (GetInt32(&id))
489                 code = PRBADARG;
490             else
491                 code =
492                     ubik_PR_ListElements(pruclient, 0, id, &alist,
493                               &over);
494             if (CodeOk(code))
495                 printf("%s\n", pr_ErrorMsg(code));
496             if (code == PRSUCCESS) {
497                 ptr = alist.prlist_val;
498                 if (over) {
499                     printf("Number of groups greater than PR_MAXGROUPS!\n");
500                     printf("Excess of %d.\n", over);
501                 }
502                 for (i = 0; i < alist.prlist_len; i++, ptr++)
503                     printf("%d\n", *ptr);
504                 free(alist.prlist_val);
505                 alist.prlist_len = 0;
506                 alist.prlist_val = 0;
507             }
508         }
509 #endif /* SUPERGROUPS */
510         else if (!strcmp(op, "nu")) {
511             /* scanf("%s",name); */
512             if (GetString(name, sizeof(name)))
513                 code = PRBADARG;
514             else
515                 code = pr_CreateUser(name, &id);
516             if (CodeOk(code))
517                 printf("%s\n", pr_ErrorMsg(code));
518             if (code == PRSUCCESS)
519                 printf("Id is %d.\n", id);
520         } else if (!strcmp(op, "ng")) {
521             /* scanf("%s",name); */
522             if (GetString(name, sizeof(name)))
523                 code = PRBADARG;
524             else
525                 code = ubik_PR_NewEntry(pruclient, 0, name, 1, oid, &id);
526             if (CodeOk(code))
527                 printf("%s\n", pr_ErrorMsg(code));
528             if (code == PRSUCCESS)
529                 printf("Id is %d.\n", id);
530         } else if (!strcmp(op, "lm")) {
531             code = ubik_PR_ListMax(pruclient, 0, &id, &gid);
532             if (CodeOk(code))
533                 printf("%s\n", pr_ErrorMsg(code));
534             if (code == PRSUCCESS)
535                 printf("Max user id is %d, max (really min) group is %d.\n",
536                        id, gid);
537         } else if (!strcmp(op, "smu")) {
538             /* scanf("%d",&id); */
539             if (GetInt32(&id))
540                 code = PRBADARG;
541             else
542                 code = ubik_PR_SetMax(pruclient, 0, id, 0);
543             if (CodeOk(code))
544                 printf("%s\n", pr_ErrorMsg(code));
545         } else if (!strcmp(op, "smg")) {
546             /* scanf("%d",&id); */
547             if (GetInt32(&id))
548                 code = PRBADARG;
549             else
550                 code = ubik_PR_SetMax(pruclient, 0, id, 1);
551             if (CodeOk(code))
552                 printf("%s\n", pr_ErrorMsg(code));
553         } else if (!strcmp(op, "sin")) {
554             /* scanf("%d",&id); */
555             if (GetInt32(&id))
556                 code = PRBADARG;
557             else
558                 code = pr_SIdToName(id, name);
559             if (CodeOk(code))
560                 printf("%s\n", pr_ErrorMsg(code));
561             if (code == PRSUCCESS)
562                 printf("id %d name %s\n", id, name);
563         } else if (!strcmp(op, "sni")) {
564             /* scanf("%s",name); */
565             if (GetString(name, sizeof(name)))
566                 code = PRBADARG;
567             else
568                 code = pr_SNameToId(name, &id);
569             if (CodeOk(code))
570                 printf("%s\n", pr_ErrorMsg(code));
571             if (code == PRSUCCESS)
572                 printf("name %s id %d\n", name, id);
573         } else if (!strcmp(op, "fih")) {
574             char tname[128];
575             struct PrUpdateEntry uentry;
576             memset(&uentry, 0, sizeof(uentry));
577             /* scanf("%s",name); */
578             if (GetString(name, sizeof(name))) {
579                 code = PRBADARG;
580                 continue;
581             }
582             code = pr_SNameToId(name, &id);
583             if (CodeOk(code)) {
584                 printf("%s\n", pr_ErrorMsg(code));
585                 continue;
586             }
587             code = pr_SIdToName(id, tname);
588             if (code == PRSUCCESS) {
589                 printf
590                     ("Warning: Id hash for %s (id %d) seems correct at the db; rehashing it anyway\n",
591                      name, id);
592 /*              continue;*/
593             }
594             uentry.Mask = PRUPDATE_IDHASH;
595             code = ubik_PR_UpdateEntry(pruclient, 0, 0, name, &uentry);
596             if (code) {
597                 printf("Failed to update entry %s (err=%d)\n", name, code);
598                 continue;
599             }
600         } else if (!strcmp(op, "fnh")) {
601             int tid;
602             struct PrUpdateEntry uentry;
603             memset(&uentry, 0, sizeof(uentry));
604             /* scanf("%d", &id); */
605             if (GetInt32(&id)) {
606                 code = PRBADARG;
607                 continue;
608             }
609             code = pr_SIdToName(id, name);
610             if (CodeOk(code)) {
611                 printf("%s\n", pr_ErrorMsg(code));
612                 continue;
613             }
614             code = pr_SNameToId(name, &tid);
615             if (code == PRSUCCESS) {
616                 printf
617                     ("Name hash for %d (name is %s) seems correct at the db; rehashing it anyway\n",
618                      id, name);
619 /*              continue;*/
620             }
621             uentry.Mask = PRUPDATE_NAMEHASH;
622             code =
623                 ubik_PR_UpdateEntry(pruclient, 0, id, "_foo_", &uentry);
624             if (code) {
625                 printf("Failed to update entry with id %d (err=%d)\n", id,
626                        code);
627                 continue;
628             }
629         }
630 #if defined(SUPERGROUPS)
631         else if (!strcmp(op, "fih")) {
632             char tname[128];
633             struct PrUpdateEntry uentry;
634             memset(&uentry, 0, sizeof(uentry));
635             /* scanf("%s",name); */
636             if (GetString(name, sizeof(name))) {
637                 code = PRBADARG;
638                 continue;
639             }
640             code = pr_SNameToId(name, &id);
641             if (CodeOk(code)) {
642                 printf("%s\n", pr_ErrorMsg(code));
643                 continue;
644             }
645             code = pr_SIdToName(id, tname);
646             if (code == PRSUCCESS) {
647                 printf
648                     ("Warning: Id hash for %s (id %d) seems correct at the db; rehashing it anyway\n",
649                      name, id);
650 /*              continue;*/
651             }
652             uentry.Mask = PRUPDATE_IDHASH;
653             code = ubik_PR_UpdateEntry(pruclient, 0, 0, name, &uentry);
654             if (code) {
655                 printf("Failed to update entry %s (err=%d)\n", name, code);
656                 continue;
657             }
658         } else if (!strcmp(op, "fnh")) {
659             int tid;
660             struct PrUpdateEntry uentry;
661             memset(&uentry, 0, sizeof(uentry));
662             /* scanf("%d", &id); */
663             if (GetInt32(&id)) {
664                 code = PRBADARG;
665                 continue;
666             }
667             code = pr_SIdToName(id, name);
668             if (CodeOk(code)) {
669                 printf("%s\n", pr_ErrorMsg(code));
670                 continue;
671             }
672             code = pr_SNameToId(name, &tid);
673             if (code == PRSUCCESS) {
674                 printf
675                     ("Name hash for %d (name is %s) seems correct at the db; rehashing it anyway\n",
676                      id, name);
677 /*              continue;*/
678             }
679             uentry.Mask = PRUPDATE_NAMEHASH;
680             code =
681                 ubik_PR_UpdateEntry(pruclient, 0, id, "_foo_", &uentry);
682             if (code) {
683                 printf("Failed to update entry with id %d (err=%d)\n", id,
684                        code);
685                 continue;
686             }
687         }
688 #endif /* SUPERGROUPS */
689         else if (!strcmp(op, "?"))
690             PrintHelp();
691         else if (!strcmp(op, "q"))
692             exit(0);
693         else
694             printf("Unknown op: '%s'! ? for help\n", op);
695     }
696     return 0;
697 }
698
699
700 static void
701 PrintHelp(void)
702 {
703     printf("cr name id owner - create entry with name and id.\n");
704     printf("wh id  - what is the offset into database for id?\n");
705     printf("du offset - dump the contents of the entry at offset.\n");
706     printf("add uid gid - add user uid to group gid.\n");
707     printf("iton id* - translate the list of id's to names.\n");
708     printf("ntoi name* - translate the list of names to ids.\n");
709     printf("del id - delete the entry for id.\n");
710     printf("dg gid - delete the entry for group gid.\n");
711     printf("rm id gid - remove user id from group gid.\n");
712     printf("l id - get the CPS for id.\n");
713     printf("lh host - get the host CPS for host.\n");
714 #if defined(SUPERGROUPS)
715     printf("lsg id - get the supergroups for id.\n");
716     printf("m id - list elements for id.\n");
717 #endif
718     printf("nu name - create new user with name - returns an id.\n");
719     printf("ng name - create new group with name - returns an id.\n");
720     printf("lm  - list max user id and max (really min) group id.\n");
721     printf("smu - set max user id.\n");
722     printf("smg - set max group id.\n");
723     printf("sin id - single iton.\n");
724     printf("sni name - single ntoi.\n");
725     printf("fih name - fix id hash for <name>.\n");
726     printf("fnh id - fix name hash for <id>.\n");
727     printf("q - quit.\n?- this message.\n");
728 }
729
730 static void
731 skip(char **s)
732 {
733     while (**s != ' ' && **s != '\0')
734         (*s)++;
735     while (**s == ' ')
736         (*s)++;
737 }