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