Linux
Application Development |
Michael K. Johnson Erik W. Troan |
/* phones.c -- simple phone database to illustrate Berkeley db */ /* This implements a very simple phone database. Full usage information is given in the text. */ #include <alloca.h> #include <db.h> #include <errno.h> #include <fcntl.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> void usage(void) { fprintf(stderr, "usage: phones -a [-f] <name> <phone>\n"); fprintf(stderr, " -d <name>\n"); fprintf(stderr, " -q <name>\n"); fprintf(stderr, " -l\n"); exit(1); } /* Opens the database $HOME/.phonedb. If writeable is nonzero, the database is opened for updating. If writeable is 0, the database is opened read-only. An appropriate lock is put on the database in either case. */ DB * openDatabase(int writeable) { DB * db; char * filename; int flags; struct flock lock; /* Set up a lock on the entire file (l_len = 0 means lock the whole file) */ lock.l_whence = SEEK_SET; lock.l_start = 0; lock.l_len = 0; /* Set the open and lock modes */ if (writeable) { flags = O_CREAT | O_RDWR; lock.l_type = F_WRLCK; } else { flags = O_RDONLY; lock.l_type = F_RDLCK; } filename = alloca(strlen(getenv("HOME")) + 20); strcpy(filename, getenv("HOME")); strcat(filename, "/.phonedb"); db = dbopen(filename, flags, 0666, DB_HASH, NULL); if (!db) { fprintf(stderr, "failed to open %s: %s\n", filename, strerror(errno)); return NULL; } /* Now that the database is open, lock it */ if (fcntl(db->fd(db), F_SETLK, &lock)) { if (errno == EAGAIN) fprintf(stderr, "the phone database is already " "locked\n"); else fprintf(stderr, "failed to lock database: %s\n", strerror(errno)); return NULL; } return db; } /* add a new record to the database; this parses the command-line arguments directly */ int addRecord(int argc, char ** argv) { DB * db; char * name, * phone; DBT key, value; int rc = 0; int overwrite = 0; /* check for our parameters; -f means overwrite an existing entry, and the name and phone number should be all that remains */ if (!argc) usage(); if (!strcmp(argv[0], "-f")) { overwrite = 1; argc--, argv++; } if (argc != 2) usage(); name = argv[0]; phone = argv[1]; /* open the database for writing */ if (!(db = openDatabase(1))) return 1; key.data = name; /* the +1 writes the trailing '\0' to the file */ key.size = strlen(name) + 1; /* if we shouldn't overwrite an existing entry, check to see if this name is already used */ if (!overwrite) { rc = db->get(db, &key, &value, 0); if (rc == -1) { fprintf(stderr, "get failed: %s\n", strerror(errno)); rc = 1; } else if (!rc) { fprintf(stderr, "%s already listed as %s\n", name, (char *) value.data); rc = 1; } else { rc = 0 ; } } /* if everything has worked so far, update the database */ if (!rc) { value.data = phone; value.size = strlen(phone) + 1; if (db->put(db, &key, &value, 0)) { fprintf(stderr, "put failed: %s\n", strerror(errno)); rc = 1; } } db->close(db); return rc; } /* looks up a name, and prints the phone number associated with it; parses the command line directly */ int queryRecord(int argc, char ** argv) { DB * db; DBT key, value; int rc; /* only one argument is expected, a name to look up */ if (argc != 1) usage(); /* open the database for reading */ if (!(db = openDatabase(0))) return 1; /* set up the key to look up */ key.data = argv[0]; key.size = strlen(argv[0]) + 1; rc = db->get(db, &key, &value, 0); if (rc == -1) { fprintf(stderr, "get failed: %s\n", strerror(errno)); rc = 1; } else if (rc) { fprintf(stderr, "%s is not listed\n", argv[0]); rc = 1; } else { printf("%s %s\n", argv[0], (char *) value.data); rc = 0; } db->close(db); return rc; } /* delete the specified record; the name is passed as a command-line argument */ int delRecord(int argc, char ** argv) { DB * db; DBT key; int rc; /* only a single argument is expected */ if (argc != 1) usage(); /* open the database for updating */ if (!(db = openDatabase(1))) return 1; /* set up the key */ key.data = argv[0]; key.size = strlen(argv[0]) + 1; rc = db->del(db, &key, 0); if (rc == -1) { fprintf(stderr, "del failed: %s\n", strerror(errno)); rc = 1; } else if (rc) { fprintf(stderr, "%s is not listed\n", argv[0]); rc = 1; } db->close(db); return rc; } /* lists all of the records in the database */ int listRecords(void) { DB * db; DBT key, value; int rc; int flags = R_FIRST; /* open the database read-only */ if (!(db = openDatabase(0))) return 1; /* iterate over all of the records */ while (!(rc = db->seq(db, &key, &value, flags))) { flags = R_NEXT; printf("%s %s\n", (char *) key.data, (char *) value.data); } if (rc == -1) { fprintf(stderr, "seq failed: %s\n", strerror(errno)); rc = 1; } else { rc = 0; } db->close(db); return rc; } int main(int argc, char ** argv) { if (argc == 1) usage(); /* look for a mode flag, and call the appropriate function with the remainder of the arguments */ if (!strcmp(argv[1], "-a")) return addRecord(argc - 2, argv + 2); else if (!strcmp(argv[1], "-q")) return queryRecord(argc - 2, argv + 2); else if (!strcmp(argv[1], "-d")) return delRecord(argc - 2, argv + 2); else if (!strcmp(argv[1], "-l")) { if (argc != 2) usage(); return listRecords(); } usage(); /* did not recognize any options */ return 0; /* doesn't get here due to usage() */ }