2 entries in / with tags FreeBSD:

fgets

The fgets function seems to have different semantics on different systems after an EOF condition under Linux (glibc) and FreeBSD. Under Linux you can happily call fgets twice in a row and it will Just Work™. Under FreeBSD, you'll have to say "Sorry!", i.e. clearerr, and it won't talk to you unless you do it. I haven't yet found out where this happens but I find this behavior rather annoying. The worst part is that this doesn't seem documented.

The following program illustrates the problem. Press Ctrl-D at the first prompt. Linux will try to read again the second time. FreeBSD won't unless you put a clearerr in there.

#include <stdio.h>

int main(int argc, const char **argv) {
  char buffer[256];
  fputs("What? ", stdout); fflush(stdout);
  if (fgets(buffer, sizeof buffer, stdin) != NULL) {
    fprintf(stdout, "Got 1: '%s'\n", buffer);
  }
  fputs("What? ", stdout); fflush(stdout);
  if (fgets(buffer, sizeof buffer, stdin) != NULL) {
    fprintf(stdout, "Got 2: '%s'\n", buffer);
  }
  return 0;
}

vlock 2 now FreeBSD compatible

vlock-2 is now FreeBSD compatible out of the box. Please test:

cg-clone http://cthulhu.c3d2.de/~toidinamai/git/vlock.git#vlock-2
cd vlock
gmake PAM_LIBS='-lpam'
# as root
gmake ROOT_GROUP=wheel VLOCK_GROUP=wheel INSTALL=ginstall install

You'll need ginstall (coreutils) for the installation. Porting was rather straight forward as console ioctls are very similar. I found FreeBSD kernel source more difficult to read, though. One example:

Linux (drivers/char/vt_ioctl.c)

/*
 * ioctl(fd, VT_ACTIVATE, num) will cause us to switch to vt # num,
 * with num >= 1 (switches to vt 0, our console, are not allowed, just
 * to preserve sanity).
 */
case VT_ACTIVATE:
  if (!perm)
    return -EPERM;
  if (arg == 0 || arg > MAX_NR_CONSOLES)
    return -ENXIO;
  arg--;
  acquire_console_sem();
  i = vc_allocate(arg);
  release_console_sem();
  if (i)
    return i;
  set_console(arg);
  return 0;

FreeBSD (sys/dev/syscons/syscons.c)

case VT_ACTIVATE:           /* switch to screen *data */
    i = (*(int *)data == 0) ? scp->index : (*(int *)data - 1);
    s = spltty();
    error = sc_clean_up(sc->cur_scp);
    splx(s);
    if (error)
        return error;
    return sc_switch_scr(sc, i);