mksnap_ffs.c revision 125107
1111716Smckusick/* 2111716Smckusick * Copyright (c) 2003 Networks Associates Technology, Inc. 3111716Smckusick * All rights reserved. 4111716Smckusick * 5111716Smckusick * This software was developed for the FreeBSD Project by Marshall 6111716Smckusick * Kirk McKusick and Network Associates Laboratories, the Security 7111716Smckusick * Research Division of Network Associates, Inc. under DARPA/SPAWAR 8111716Smckusick * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS 9111716Smckusick * research program. 10111716Smckusick * 11111716Smckusick * Redistribution and use in source and binary forms, with or without 12111716Smckusick * modification, are permitted provided that the following conditions 13111716Smckusick * are met: 14111716Smckusick * 1. Redistributions of source code must retain the above copyright 15111716Smckusick * notice, this list of conditions and the following disclaimer. 16111716Smckusick * 2. Redistributions in binary form must reproduce the above copyright 17111716Smckusick * notice, this list of conditions and the following disclaimer in the 18111716Smckusick * documentation and/or other materials provided with the distribution. 19111716Smckusick * 3. The names of the authors may not be used to endorse or promote 20111716Smckusick * products derived from this software without specific prior written 21111716Smckusick * permission. 22111716Smckusick * 23111716Smckusick * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 24111716Smckusick * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25111716Smckusick * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26111716Smckusick * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 27111716Smckusick * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28111716Smckusick * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29111716Smckusick * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30111716Smckusick * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31111716Smckusick * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32111716Smckusick * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33111716Smckusick * SUCH DAMAGE. 34111716Smckusick * 35111716Smckusick * $FreeBSD: head/sbin/mksnap_ffs/mksnap_ffs.c 125107 2004-01-27 19:28:13Z des $ 36111716Smckusick */ 37111716Smckusick 38111716Smckusick#include <sys/param.h> 39111716Smckusick#include <sys/mount.h> 40111716Smckusick#include <sys/stat.h> 41111716Smckusick#include <ufs/ufs/ufsmount.h> 42111716Smckusick#include <err.h> 43111716Smckusick#include <errno.h> 44111725Smckusick#include <fcntl.h> 45111716Smckusick#include <grp.h> 46122035Smckusick#include <limits.h> 47111716Smckusick#include <stdio.h> 48111716Smckusick#include <stdlib.h> 49111716Smckusick#include <string.h> 50111716Smckusick#include <sysexits.h> 51111716Smckusick#include <unistd.h> 52111716Smckusick 53121706Strhodesvoid usage(void); 54121706Strhodes 55111716Smckusickint 56111716Smckusickmain(int argc, char **argv) 57111716Smckusick{ 58122035Smckusick char *dir, *cp, path[PATH_MAX]; 59125103Smckusick struct statfs stfsbuf; 60111716Smckusick struct ufs_args args; 61111716Smckusick struct group *grp; 62111725Smckusick struct stat stbuf; 63111725Smckusick int fd; 64111716Smckusick 65111716Smckusick if (argc != 3) 66111716Smckusick usage(); 67111716Smckusick 68111716Smckusick dir = argv[1]; 69111716Smckusick args.fspec = argv[2]; 70111716Smckusick 71122035Smckusick /* 72122035Smckusick * Check that the user running this program has permission 73122035Smckusick * to create and remove a snapshot file from the directory 74122035Smckusick * in which they have requested to have it made. If the 75122035Smckusick * directory is sticky and not owned by the user, then they 76122035Smckusick * will not be able to remove the snapshot when they are 77122035Smckusick * done with it. 78122035Smckusick */ 79122035Smckusick if (strlen(args.fspec) >= PATH_MAX) 80122035Smckusick errx(1, "pathname too long %s", args.fspec); 81122035Smckusick cp = strrchr(args.fspec, '/'); 82122035Smckusick if (cp == NULL) { 83122035Smckusick strlcpy(path, ".", PATH_MAX); 84122035Smckusick } else if (cp == args.fspec) { 85122035Smckusick strlcpy(path, "/", PATH_MAX); 86122035Smckusick } else { 87122035Smckusick strlcpy(path, args.fspec, cp - args.fspec + 1); 88122035Smckusick } 89125107Sdes if (statfs(path, &stfsbuf) < 0) 90125103Smckusick err(1, "%s", path); 91122035Smckusick if (stat(path, &stbuf) < 0) 92122035Smckusick err(1, "%s", path); 93122035Smckusick if (!S_ISDIR(stbuf.st_mode)) 94122035Smckusick errx(1, "%s: Not a directory", path); 95122035Smckusick if (access(path, W_OK) < 0) 96122035Smckusick err(1, "Lack write permission in %s", path); 97122035Smckusick if ((stbuf.st_mode & S_ISTXT) && stbuf.st_uid != getuid()) 98122035Smckusick errx(1, "Lack write permission in %s: Sticky bit set", path); 99122035Smckusick 100122035Smckusick /* 101122035Smckusick * Having verified access to the directory in which the 102122035Smckusick * snapshot is to be built, proceed with creating it. 103122035Smckusick */ 104111716Smckusick if ((grp = getgrnam("operator")) == NULL) 105111716Smckusick errx(1, "Cannot retrieve operator gid"); 106125103Smckusick if (mount("ffs", dir, MNT_UPDATE | MNT_SNAPSHOT | stfsbuf.f_flags, 107125103Smckusick &args) < 0) 108111716Smckusick err(1, "Cannot create %s", args.fspec); 109111725Smckusick if ((fd = open(args.fspec, O_RDONLY)) < 0) 110111725Smckusick err(1, "Cannot open %s", args.fspec); 111111725Smckusick if (fstat(fd, &stbuf) != 0) 112111725Smckusick err(1, "Cannot stat %s", args.fspec); 113111725Smckusick if ((stbuf.st_flags & SF_SNAPSHOT) == 0) 114111725Smckusick errx(1, "File %s is not a snapshot", args.fspec); 115111725Smckusick if (fchown(fd, -1, grp->gr_gid) != 0) 116111716Smckusick err(1, "Cannot chown %s", args.fspec); 117111725Smckusick if (fchmod(fd, S_IRUSR | S_IRGRP) != 0) 118111716Smckusick err(1, "Cannot chmod %s", args.fspec); 119111716Smckusick 120111716Smckusick exit(EXIT_SUCCESS); 121111716Smckusick} 122121707Strhodes 123121707Strhodesvoid 124121707Strhodesusage() 125121707Strhodes{ 126121707Strhodes 127121707Strhodes fprintf(stderr, "usage: mksnap_ffs mountpoint snapshot_name\n"); 128121707Strhodes exit(EX_USAGE); 129121707Strhodes} 130