home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume21 / uoodoo / part01 / uoodoo.c < prev   
C/C++ Source or Header  |  1991-07-27  |  20KB  |  717 lines

  1. /****************************************************************************
  2.  *
  3.  *    uoodoo - create and update a directory of symbolic links which point
  4.  *    to users' home directories.
  5.  *
  6.  *    Usage:
  7.  *    uoodoo [-w] [-d] [-a] [-c] [-u u-directory] [dir1 [dir2] ... ]
  8.  *
  9.  *    Arguments:
  10.  *        Directories which contain users' home directory entries.
  11.  *        Different argument ordering may produce different results.
  12.  *        See the man page for further details.
  13.  *
  14.  *    Options:
  15.  *    -a    Report what actions, if any, are performed.
  16.  *    -c    Create output, but do not perform any actions.
  17.  *    -d    Debug mode. Creates lots of output.
  18.  *    -p link-path
  19.  *        Use the "link-path" as a path in the password file to
  20.  *        indicate that the home directory is a symbolic link.
  21.  *    -u u-directory
  22.  *        Use the "u-directory" instead of the default (/u) directory.
  23.  *    -w    Print warnings: home directory conflicts, multiple password
  24.  *        password file entries, and entries in the u-directory which
  25.  *        are not symbolic links.
  26.  *
  27.  *    Installation:
  28.  *        Choose either the "BSD_LIKE" or "SYSV_LIKE" variable in
  29.  *        the Makefile to include the proper header files for the
  30.  *        directory libraries. Also add the proper library to 
  31.  *        link if your system requires a library to access a
  32.  *        YP/NIS version of getpwent(3). Type make. Create /u
  33.  *        before running.
  34.  *
  35.  * Copyright (c) 1991 by Shelley L. Shostak.
  36.  * All rights reserved.
  37.  *
  38.  * Redistribution and use in source and binary forms are permitted
  39.  * provided that the above copyright notice and this paragraph are
  40.  * duplicated in all such forms and that any documentation,
  41.  * advertising materials, and other materials related to such
  42.  * distribution and use acknowledge that the software was developed
  43.  * by Shelley L. Shostak.
  44.  *
  45.  * Any use of this software is at the user's own risk.
  46.  *
  47.  * Send comments and bugs to sls@cs.duke.edu.
  48.  *
  49.  ****************************************************************************/
  50.  
  51. #ifndef lint
  52. static char SccsId[] = "@(#)uoodoo.c    1.15\t7/25/91";
  53. #endif
  54.  
  55. #include <stdio.h>
  56. #include <sys/types.h>
  57.  
  58. #ifdef SYSV_LIKE /* SunOS, SGI, UNICOS */
  59. #include <dirent.h>
  60. #define DIRENTRY struct dirent
  61. #endif
  62.  
  63. #ifdef BSD_LIKE /* SunOS, Convex */
  64. #include <sys/dir.h>
  65. #define DIRENTRY struct direct
  66. #endif
  67.  
  68. #include <errno.h>
  69. #include <sys/param.h>
  70. #include <pwd.h>
  71. #include <sys/stat.h>
  72. #include <strings.h>
  73.  
  74. #define MAXIDLEN    16    /* Maximum length of login name */
  75. #define MAXUSERS    2500    /* Maximum entries from the passwd file */
  76. #define MAXHDLEN    128    /* Maximum length of home directory entry */
  77. #define MAXLINKLEN    144    /* Maximum length of sym link name */
  78. #define DEFAULTUDIR    "/u"    /* The default dir. containing sym. links */
  79.  
  80. #define        SUCCEEDED    0   /* return code tokens */
  81. #define        FAILED        1
  82. #define        CONFLICT    1
  83. #define        FATAL        2
  84.  
  85. #define        TRUE        1
  86. #define        FALSE        0
  87.  
  88. struct userinfo {
  89.     char    name[MAXIDLEN];        /* login name for user */
  90.     char    homedir[MAXHDLEN];    /* contains what we think the users real
  91.                        home directory is at any time */
  92.     char    conflictdir[MAXHDLEN];    /* store conflicts here */
  93.     int    status;        /* Unless we have found a link entry, the
  94.                  * status flag indicates what type of home
  95.                  * directory the user has at any given time and
  96.                  * if we found a real directory for the user.
  97.                  */
  98.     int    action;        /* The action to be performed on this entry. */
  99. } user[MAXUSERS];
  100.  
  101. /* Possible flags for status: */
  102. #define        HD_IS_LINK    001   /* home dir. is a symbolic link */
  103. #define        HD_IS_DIR    002   /* home dir. is a real directory */
  104. #define        DIR_FOUND    004   /* a directory for this user was found */
  105. #define        HD_CNFLCT    010   /* we discovered a conflict */
  106.  
  107. /* Possible flags for action: */
  108. #define        NONE        001   /* entry ok, don't do anything */
  109. #define        ADD        002   /* no u-dir entry, add one */
  110. #define        REMOVE        004   /* remove u-dir entry */
  111. #define        UPDATE        010   /* update u-dir, HD has changed */
  112.  
  113. unsigned int nusers = 0;
  114. int errflg, aflg, cflg, pflg, uflg, wflg, dflg;  /* option flags */
  115. int action = FALSE;        /* reports the actions which uoodoo takes */
  116. int debug = FALSE;        /* debug mode prints lots of output */
  117. int warn = FALSE;        /* warn prints other interesting info */
  118. int doit = TRUE;        /* if false, then the action will not be taken */
  119. int endsort;            /* Last sorted userinfo table entry (kludge) */
  120. char usage[ ] =     "[-w] [-d] [-a] [-c] [-u udir] [dir1 [dir2] ... ]";
  121. char linkdir[MAXLINKLEN] = DEFAULTUDIR;    /* directory where links can be found */
  122. char linkpath[MAXLINKLEN] = DEFAULTUDIR; /* path which indicates a link */
  123. char *program;            /* Our name */
  124.  
  125. int doargs();
  126. int readpw();
  127. int lookdir();
  128. int readu();
  129. int actions();
  130. int add_sl();
  131. int rm_sl();
  132. int update_sl();
  133. int namecmp();
  134. char *cstat();
  135. void exit();
  136. int checkpwent();
  137. struct userinfo *addtabent();
  138. struct userinfo *find();
  139. struct userinfo *search();
  140.  
  141. main(argc, argv)
  142.     int argc;
  143.     char *argv[ ];
  144. {
  145.     int dirlist;
  146.     int error = 0;
  147.     char dirname[MAXHDLEN];
  148.  
  149.     program = *argv;
  150.     setlinebuf(stdout);    /* use line buffering, intermix stderr stdio */
  151.     dirlist = doargs(argc, argv);
  152.     if (uflg) (void) printf("/u override %s\n", linkdir);
  153.     if (cflg) (void) printf("Just checking\n");
  154.     (void) strcat(linkdir, "/");    /* turn dir name into a path */
  155.     if (readpw() != SUCCEEDED)    /* build user table from passwd file */
  156.         exit (FAILED);        /* need to make MAXUSERS larger */
  157.     /* treat the remaining arguments as directory names */
  158.     while (argv[dirlist] != NULL ) {
  159.         (void) strcpy(dirname, argv[dirlist++]);
  160.         error += lookdir(dirname);
  161.     }
  162.     if (error)            /* quit if ANY directory is empty */
  163.         exit (FATAL);
  164.     if (readu() == FATAL)        /* read the directory of links */
  165.         exit (FAILED);
  166.     if (actions() != SUCCEEDED)    /* run through table entries */
  167.         exit (FAILED);
  168.     exit (SUCCEEDED);
  169.     /* NOTREACHED */
  170. }
  171.  
  172. /*
  173.  *    Process the command line arguments. Returns one greater than the
  174.  *    argument number of the last option flag, which is the first 
  175.  *    directory to process.
  176.  */
  177.  
  178. doargs (argc, argv)
  179.     int argc;
  180.     char **argv;
  181. {
  182.     int c;
  183.  
  184.     extern char *optarg;
  185.     extern int optind;
  186.     int getopt();
  187.  
  188.     errflg = aflg = cflg = dflg = pflg = uflg = wflg = 0;
  189.     while ((c = getopt(argc, argv, "acdp:u:w")) != -1 ) {
  190.         switch (c) {
  191.         case 'a':    /* report actions */
  192.             if (aflg)
  193.                 ++errflg;
  194.             else {
  195.                 ++aflg;
  196.                 action = TRUE;
  197.             }
  198.             break;
  199.         case 'c':    /* don't actually do anything */
  200.             if (cflg)
  201.                 ++errflg;
  202.             else {
  203.                 ++cflg;
  204.                 doit = FALSE;
  205.             }
  206.             break;
  207.         case 'd':    /* print diagnostic messages */
  208.             if (dflg)
  209.                 ++errflg;
  210.             else {
  211.                 ++dflg;
  212.                 debug = TRUE;
  213.                 warn = TRUE;
  214.                 action = TRUE;
  215.             }
  216.             break;
  217.         case 'p':    /* override default link path */
  218.             if (pflg)
  219.                 ++errflg;
  220.             else {
  221.                 ++pflg;
  222.                 (void) strcpy(linkpath, optarg);
  223.             }
  224.             break;
  225.         case 'u':    /* override default link directory */
  226.             if (uflg)
  227.                 ++errflg;
  228.             else {
  229.                 ++uflg;
  230.                 (void) strcpy(linkdir, optarg);
  231.             }
  232.             if (!pflg)    /* by default, linkpath same as linkdir */
  233.                 (void) strcpy(linkpath, optarg);
  234.             break;
  235.         case 'w':    /* warn */
  236.             if (wflg)
  237.                 ++errflg;
  238.             else {
  239.                 ++wflg;
  240.                 warn = TRUE;
  241.             }
  242.             break;
  243.         case '?':    /* unknown option */
  244.             ++errflg;
  245.             break;
  246.         }
  247.         if (errflg) {
  248.             (void) fprintf(stderr, "usage: %s %s\n", *argv, usage);
  249.             exit (FAILED);
  250.         }
  251.     }
  252.     return (optind);
  253. }
  254.  
  255. /*
  256.  *    Read the password file filling in all three members of the unserinfo
  257.  *    structure for each user. Returns FAILED if the array isn't large
  258.  *    enough to hold all of the entries from the password file.
  259.  *
  260.  *    NOTE:    This routine uses getpwent() which may behave differently
  261.  *        on different systems.
  262.  */
  263.  
  264. readpw()
  265. {
  266.     struct passwd *pwentry;
  267.     struct userinfo *puser;
  268.     int qsort();
  269.     char linkhomedir[MAXHDLEN];    /* If HD is a link, this is its name */
  270.  
  271.     debug && printf("\n+++++ FETCHING PASSWORD ENTRIES +++++\n\n");
  272.     puser = user;
  273.     while ((pwentry = getpwent()) != NULL) {
  274.         /* We only use the FIRST entry returned if getpwent() returns
  275.            more than one entry per login name */
  276.         if (find(pwentry->pw_name) != NULL) {
  277.             warn && printf("Multiple password entries for %s\n",
  278.                          pwentry->pw_name);
  279.             continue;
  280.         }
  281.         /* YP password entries have probably been scrutinized by YP
  282.          * for errors, but local files can contain typing errors. */
  283.         if (checkpwent(pwentry) != 0)
  284.             continue;
  285.         if ((puser = addtabent(pwentry->pw_name)) == NULL)
  286.             return (FATAL);
  287.         (void) strncpy(linkhomedir, linkpath, sizeof(linkhomedir));
  288.         (void) strncat(linkhomedir, "/", sizeof(linkhomedir));
  289.         (void) strncat(linkhomedir, pwentry->pw_name, sizeof(linkhomedir));
  290.         if (strncmp(linkhomedir, pwentry->pw_dir, strlen(linkhomedir)) == 0 )
  291.             puser->status = HD_IS_LINK;    /* HD is a sym. link */
  292.         else {
  293.             puser->status = HD_IS_DIR;    /* HD is a directory */
  294.             (void) strcpy(puser->homedir, pwentry->pw_dir);
  295.         }
  296.         /* Until we find out differently, need to add a u-dir entry */
  297.         puser->action = ADD;
  298.         debug && printf("user=(%s) HD=(%s) status=(%s)\n",
  299.                        puser->name, puser->homedir, cstat(puser->status));
  300.     }
  301.     debug && printf("FOUND %d USERS IN PASSWORD FILE\n", nusers);
  302.     endsort = nusers;
  303.     qsort((char *)user, endsort, sizeof(struct userinfo), namecmp);
  304.     return (SUCCEEDED);
  305. }    
  306.  
  307. /*    Look at the entries in a directory. If a match is found with a user
  308.  *    name, update the status flag, and possibly the homedir field. Warn
  309.  *    if there is more than one directory for a single user. An empty
  310.  *    directory indicates that there is a fatal error, such as a mount
  311.  *    point with no file system mounted. A special error code (FATAL)
  312.  *    indicates en empty directory. 
  313.  */
  314.  
  315. lookdir (direct)
  316.     char *direct;
  317. {
  318.     int rc = SUCCEEDED;
  319.     int empty;            /* flag indicating an empty dir. */
  320.     char compdirname[MAXHDLEN];    /* complete directory name */
  321.     struct userinfo *where;
  322.     DIR *dirp;
  323.     DIR *opendir();
  324.     DIRENTRY *readdir();
  325.     DIRENTRY *dp;
  326.  
  327.     debug && printf("\n+++++ READING ARGUMENT DIRECTORIES +++++\n\n");
  328.     warn && printf("\n%s:\n", direct);
  329.     if ((dirp = opendir(direct)) == NULL) {
  330.         (void) fprintf(stderr, "Cannot open %s\n", direct);
  331.         return (FATAL);
  332.     }
  333.     (void) strcat(direct, "/");
  334.     empty = TRUE;
  335.     for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
  336.         if (!strcmp(dp->d_name, ".") ||
  337.             !strcmp(dp->d_name, "..") ||
  338.             !strcmp(dp->d_name, "quotas") ||
  339.             !strcmp(dp->d_name, "lost+found"))
  340.             continue;
  341.         empty = FALSE;
  342.         (void) strcpy(compdirname, direct);
  343.         (void) strcat(compdirname, dp->d_name);
  344.         /*
  345.          * There is no guarantee that the entry is a directory.
  346.          * Using stat to obtain the file type has some potential
  347.          * pitfalls so we choose to allow a users home directory
  348.          * to become a plain file. Hopefully the user already has a
  349.          * home directory and a conflict will be generated.
  350.          *
  351.          * Look for the directory name in the user table, so that the
  352.          * status flag can be upgraded to indicate an existing directory.
  353.          */
  354.         if ((where = search(dp->d_name)) == NULL) {
  355.             warn && printf("No such user: %s\n", dp->d_name);
  356.             continue;
  357.         }
  358.         /* A dir was already found */
  359.         if (where->status & DIR_FOUND) {
  360.             where->status |= HD_CNFLCT;
  361.             (void) strcpy(where->conflictdir, (strcmp(where->conflictdir, where->homedir) == 0) ?
  362.                       compdirname : where->conflictdir);
  363.             warn && printf("Conflict. %s: %s  %s\n",
  364.                        where->name, where->homedir,
  365.                        where->conflictdir);
  366.             /* Conflict is an error if passwd HD is /u/user
  367.              * but complain about errors later */
  368.         } else {
  369.             /* do not update home directory if the password 
  370.              * home directory is a real directory
  371.              */
  372.             /* save only the FIRST directory found
  373.              * if the paswd entry is a link */
  374.             if (where->status == HD_IS_LINK)
  375.                 (void) strcpy(where->homedir, compdirname);
  376.             (void) strcpy(where->conflictdir, compdirname);
  377.             where->status |= DIR_FOUND;
  378.         }
  379.         debug && printf("user=(%s) HD=(%s) status=(%s)\n",
  380.                        where->name, where->homedir, cstat(where->status));
  381.     }
  382.     if (empty) {
  383.         (void) fprintf(stderr, "Quitting: empty directory encountered: %s\n", direct);
  384.         rc = FATAL;
  385.     }
  386.     (void) closedir(dirp);
  387.     return (rc);
  388. }
  389.  
  390. /*
  391.  *    Read symbolic link directory. During this process remove or update
  392.  *    the symbolic link depending on the status flag. If a symbolic link
  393.  *    is found for any user, the user's status flag is upgraded to DONE.
  394.  */
  395.  
  396. readu ()
  397. {
  398.     int nchars;
  399.     int rc = SUCCEEDED;
  400.     char upath[MAXLINKLEN], link[MAXLINKLEN];
  401.     DIR *opendir();
  402.     DIR *dirp;
  403.     DIRENTRY *readdir();
  404.     DIRENTRY *dp;
  405.     struct stat buf;
  406.     struct userinfo *where;
  407.     int lstat();
  408.     int readlink();
  409.  
  410.     debug && printf("\n+++++ READING AND PROCESSING %s +++++\n\n", linkdir);
  411.     if ((dirp = opendir(linkdir)) == NULL) {
  412.         perror(program);
  413.         return (FATAL);
  414.     }
  415.     for (dp = readdir(dirp); dp != NULL; dp = readdir(dirp)) {
  416.         if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, ".."))
  417.             continue;
  418.         (void) strcpy(upath, linkdir);
  419.         (void) strcat(upath, dp->d_name);
  420.         /* Do not stat the entry. If it is a directory then
  421.          * allow the calls to unlink and symlink to fail.
  422.          *
  423.          * Look in the user table for an entry.
  424.          */
  425.         where = search(dp->d_name);
  426.         if (where == NULL) {    /* No user exists, rm the link */
  427.             warn && printf("No such user: %s%s\n",
  428.                            linkdir, dp->d_name);
  429.             if ((where = addtabent(dp->d_name)) == NULL)
  430.                 return(FAILED);
  431.             else
  432.                 where->action = REMOVE;
  433.             continue;
  434.         }
  435.         where->action = NONE;    /* Found entry, assume it's OK */
  436.         /* Make sure entry is a link before we read its value */
  437.         if (lstat(upath, &buf) != 0) {
  438.             perror(program);
  439.             continue;
  440.         }
  441.         if ((buf.st_mode & S_IFMT) != S_IFLNK) {
  442.             warn && printf("%s is not a symbolic link\n", upath);
  443.             where->action = REMOVE;
  444.             continue;
  445.         }
  446.         if ((nchars = readlink(upath, link, (int)(sizeof(link)-1))) == 0) {
  447.             perror(program);
  448.             continue;
  449.         }
  450.         link[nchars] = '\0';
  451.         /* Update link if the link should point elsewhere AND...
  452.          * ... if the passwd entry is a link, there is no conflict */
  453.         if (strcmp(link, where->homedir) != 0 &&
  454.             (!(where->status & HD_IS_LINK) ||
  455.             (where->status & HD_IS_LINK && !(where->status & HD_CNFLCT)))) {
  456.             debug && printf("---> U-DIR ENTRY BEING UPDATED (%s) -> (%s)\n",
  457.                            where->homedir, upath);
  458.             where->action = UPDATE;
  459.         }
  460.     }
  461.     (void) closedir(dirp);
  462.     return (rc);
  463. }
  464.  
  465. /*    Go through table and process entries which are not DONE. The only
  466.  *    action left to take is to add entries to the sym link directory,
  467.  *    if the home directory is not a reference to the symbolic link
  468.  *    we are trying to create.
  469.  */
  470.  
  471. actions()
  472. {
  473.     struct userinfo *userp;
  474.     char upath[MAXLINKLEN];
  475.     int rc = SUCCEEDED;
  476.  
  477.     debug && printf("\n+++++ CLEANING UP +++++\n\n", linkdir);
  478.     warn && printf("\n\n");
  479.     for (userp = user; (userp->name)[0] != '\0'; userp++) {
  480.         (void) strcpy(upath, linkdir);
  481.         (void) strcat(upath, userp->name);
  482.         if ((userp->status & (HD_IS_LINK | HD_CNFLCT)) == (HD_IS_LINK | HD_CNFLCT))
  483.             (void) fprintf(stderr, "Ambiguity: %s -> %s, %s\n",
  484.                        upath, userp->homedir, userp->conflictdir);
  485.         switch (userp->action) {
  486.         case NONE:
  487.             break;
  488.         case REMOVE:
  489.             if (rm_sl(upath) == FAILED)
  490.                 rc = FAILED;
  491.             break;
  492.         case UPDATE:
  493.             /* If this equality is true, then we didn't find a
  494.              * directory on any filesystem for this user */
  495.             if (userp->status == HD_IS_LINK) {
  496.                 (void) fprintf(stderr, "Attempt to update nonexistent link for %s.\n",
  497.                            userp->name);
  498.                 rc = FAILED;
  499.                 break;
  500.             }
  501.             if (update_sl(upath, userp->homedir) != SUCCEEDED)
  502.                 rc = FAILED;
  503.             break;
  504.         case ADD:
  505.             /* If this equality is true, then we didn't find a
  506.              * directory on any filesystem for this user */
  507.             if (userp->status == HD_IS_LINK) {
  508.                 (void) fprintf(stderr, "Attempt to add nonexistent link for %s.\n",
  509.                            userp->name);
  510.                 rc = FAILED;
  511.             } else {
  512.             /* Directory may be nonexistent, but DON'T stat it */
  513.                 debug && printf("---> ADDING user=(%s) HD=(%s) status=(%s)\n",
  514.                                userp->name, userp->homedir, cstat(userp->status));
  515.                 if (add_sl(upath, userp->homedir) != SUCCEEDED)
  516.                     rc = FAILED;
  517.                 /* If there was more than one directory, we should tell
  518.                  * someone about it. */
  519.                 if ((userp->status & (HD_IS_LINK | HD_CNFLCT)) == (HD_IS_LINK | HD_CNFLCT))
  520.                     (void) fprintf(stderr, "Arbitrary home directory for %s.\n", userp->name);
  521.             }
  522.             break;
  523.         default:
  524.             break;
  525.         }
  526.         debug && printf("user=(%s) HD=(%s) status=(%s)\n",
  527.                        userp->name, userp->homedir, cstat(userp->status));
  528.     }
  529.     return (rc);
  530. }
  531.  
  532. /*
  533.  *    Given a user name and a home directory string, create a symbolic
  534.  *    link in the link directory. Returns FAILED if the link could
  535.  *    not be created.
  536.  */
  537.  
  538. add_sl (link, homedir)
  539.     char *link;
  540.     char *homedir;
  541. {
  542.     int rc = SUCCEEDED;
  543.     int symlink();
  544.  
  545.     action && printf("Creating %s -> %s\n", link, homedir);
  546.     if (doit && symlink(homedir, link) != 0) {
  547.         (void) fprintf(stderr, "%s: add_sl: ", program);
  548.         perror((char *)NULL);
  549.         rc = FAILED;
  550.     }
  551.     return rc;
  552. }
  553.  
  554. /*
  555.  *    Given a user name, remove a symbolic link in the link directory.
  556.  *    Returns FAILED if the link could not be removed.
  557.  */
  558.  
  559. rm_sl (link)
  560.     char *link;
  561. {
  562.     int rc = SUCCEEDED;
  563.     int unlink();
  564.  
  565.     action && printf("Removing %s\n", link);
  566.     if (doit && unlink(link) != 0) {
  567.         (void) fprintf(stderr, "%s: rm_sl: ", program);
  568.         perror((char *)NULL);
  569.         rc = FAILED;
  570.     }
  571.     return rc;
  572. }
  573.  
  574. /*
  575.  *    Given a user name and a home directory string, update the symbolic
  576.  *    link in the link directory. Returns FAILED if the link could
  577.  *    not be updated.
  578.  */
  579.  
  580. update_sl (link, homedir)
  581.     char *link;
  582.     char *homedir;
  583. {
  584.     int rc = SUCCEEDED;
  585.     int symlink();
  586.     int unlink();
  587.  
  588.     action && printf("Updating %s -> %s\n", link, homedir);
  589.     if (doit && (unlink(link) != 0 || symlink(homedir, link) != 0)) {
  590.         (void) fprintf(stderr, "%s: update_sl: ", program);
  591.         perror((char *)NULL);
  592.         rc = FAILED;
  593.     }
  594.     return rc;
  595. }
  596.  
  597. /*
  598.  *    Compare names in the userinfo structure.
  599.  */
  600.  
  601. namecmp(struct1, struct2)
  602.     struct userinfo *struct1, *struct2;
  603. {
  604.     return (strcmp (struct1->name, struct2->name));
  605. }
  606.  
  607. /*
  608.  *    Given a user name, reserve a table entry. Puts name in member field
  609.  *    and zeros/nulls the remaining fields. Returns a pointer to the
  610.  *    added structure entry, or NULL if there was no space available.
  611.  */
  612.  
  613. struct userinfo *
  614. addtabent(pw_name)
  615.     char *pw_name;
  616. {
  617.     static struct userinfo *nextentry = user;
  618.  
  619.     if (nextentry > &user[MAXUSERS]) {
  620.         (void) fprintf(stderr,    "Not enough space allocated for more than %d users\n",
  621.             MAXUSERS);
  622.         return(NULL);
  623.     }
  624.     (void) strcpy(nextentry->name, pw_name);
  625.     nusers++;
  626.     return(nextentry++);
  627. }
  628.  
  629. /*
  630.  * Linear search for "name" in the name member of the array users. Returns
  631.  * address in name string within the struct array if found, otherwise returns
  632.  * NULL if not found.
  633.  */
  634.  
  635. struct userinfo *
  636. find (name)
  637.     char *name;
  638. {
  639.     int i;
  640.  
  641.     for (i = 0; i < nusers; i++) {
  642.         if (strcmp(name, user[i].name) == 0)
  643.             return (&user[i]);
  644.     }
  645.     return (NULL);
  646. }
  647.  
  648. /*
  649.  * Binary search for "name" in the name member of the array users. Returns
  650.  * address in name string within the struct array if found, otherwise returns
  651.  * NULL if not found.
  652.  */
  653.  
  654. struct userinfo *
  655. search (name)
  656.     char *name;
  657. {
  658.     int low, mid, high;
  659.     int comp;
  660.  
  661.     low = 0;
  662. /*    high = nusers - 1;
  663. */
  664.     high = endsort - 1;
  665.     while (low <= high) {
  666.         mid = (low + high) / 2;
  667.         comp = strcmp(name, user[mid].name);
  668.         if (comp < 0)
  669.             high = mid - 1;
  670.         else if (comp > 0)
  671.             low = mid + 1;
  672.         else
  673.             return (&user[mid]);
  674.     }
  675.     return (NULL);
  676. }
  677.  
  678. /*
  679.  * Convert the status flag into a meaningful string. Returns pointer to
  680.  * a string.
  681.  */
  682.  
  683. char *
  684. cstat(status)
  685.     int status;
  686. {
  687.     static char statstring[128];
  688.  
  689.     statstring[0] = '\0';
  690.     if (status & HD_IS_LINK)
  691.         (void) strcat(statstring, "HD_IS_LINK ");
  692.     if (status & HD_IS_DIR)
  693.         (void) strcat(statstring, "HD_IS_DIR ");
  694.     if (status & DIR_FOUND)
  695.         (void) strcat(statstring, "DIR_FOUND ");
  696.     if (status & HD_CNFLCT)
  697.         (void) strcat(statstring, "HD_CNFLCT ");
  698.     return(statstring);
  699. }
  700.  
  701. /*
  702.  *    Check the password entry for a valid loginid and a
  703.  *    non-null home directory.
  704.  */
  705.  
  706. checkpwent(pwent)
  707.     struct passwd *pwent;
  708. {
  709.     /* Sun's getpwent ignores a null login-id, but check anyway */
  710.     if (*pwent->pw_name == '\0' || *pwent->pw_dir == '\0') {
  711.         (void) fprintf(stderr, "Problems with password entry: user=(%s), HD=(%s)\n",
  712.                     pwent->pw_name, pwent->pw_dir);
  713.         return(1);
  714.     }
  715.     return(0);
  716. }
  717.