inet6: only mark autoconf addresses tentative if detached
[dragonfly.git] / sbin / mount_cd9660 / mount_cd9660.c
1 /*
2  * Copyright (c) 1992, 1993, 1994
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley
6  * by Pace Willisson (pace@blitz.com).  The Rock Ridge Extension
7  * Support code is derived from software contributed to Berkeley
8  * by Atsushi Murai (amurai@spec.co.jp).
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  * @(#)mount_cd9660.c   8.7 (Berkeley) 5/1/95
35  * $FreeBSD: src/sbin/mount_cd9660/mount_cd9660.c,v 1.15.2.3 2001/03/14 12:05:01 bp Exp $
36  */
37
38 #include <sys/cdio.h>
39 #include <sys/param.h>
40 #include <sys/mount.h>
41 #include <sys/iconv.h>
42 #include <sys/linker.h>
43 #include <sys/module.h>
44 #include <vfs/isofs/cd9660/cd9660_mount.h>
45
46 #include <ctype.h>
47 #include <err.h>
48 #include <errno.h>
49 #include <fcntl.h>
50 #include <grp.h>
51 #include <mntopts.h>
52 #include <pwd.h>
53 #include <stdlib.h>
54 #include <stdio.h>
55 #include <string.h>
56 #include <locale.h>
57 #include <sysexits.h>
58 #include <unistd.h>
59
60 struct mntopt mopts[] = {
61         MOPT_STDOPTS,
62         MOPT_UPDATE,
63         { "extatt", 0, ISOFSMNT_EXTATT, 1 },
64         { "gens", 0, ISOFSMNT_GENS, 1 },
65         { "rrip", 1, ISOFSMNT_NORRIP, 1 },
66         { "joliet", 1, ISOFSMNT_NOJOLIET, 1 },
67         { "strictjoliet", 1, ISOFSMNT_BROKENJOLIET, 1 },
68         MOPT_NULL
69 };
70
71 static gid_t    a_gid(const char *);
72 static uid_t    a_uid(const char *);
73 static mode_t   a_mask(const char *);
74 static int      set_charset(struct iso_args *args, const char *cs_local);
75 static int      get_ssector(const char *dev);
76 static void     usage(void);
77
78 int
79 main(int argc, char **argv)
80 {
81         struct stat sb;
82         struct iso_args args;
83         int ch, mntflags, opts, set_mask, set_dirmask;
84         char *dev, *dir, mntpath[MAXPATHLEN];
85         struct vfsconf vfc;
86         int error, verbose;
87         const char *cs_local;
88
89         mntflags = opts = set_mask = set_dirmask = verbose = 0;
90         memset(&args, 0, sizeof args);
91         args.ssector = -1;
92         while ((ch = getopt(argc, argv, "bC:egG:jm:M:o:rs:U:v")) != -1)
93                 switch (ch) {
94                 case 'b':
95                         opts |= ISOFSMNT_BROKENJOLIET;
96                         break;
97                 case 'C':
98                         cs_local = kiconv_quirkcs(optarg, KICONV_VENDOR_MICSFT);
99                         if (set_charset(&args, cs_local) == -1)
100                                 err(EX_OSERR, "cd9660_iconv");
101                         opts |= ISOFSMNT_KICONV;
102                         break;
103                 case 'e':
104                         opts |= ISOFSMNT_EXTATT;
105                         break;
106                 case 'g':
107                         opts |= ISOFSMNT_GENS;
108                         break;
109                 case 'G':
110                         opts |= ISOFSMNT_GID;
111                         args.gid = a_gid(optarg);
112                         break;
113                 case 'j':
114                         opts |= ISOFSMNT_NOJOLIET;
115                         break;
116                 case 'm':
117                         args.fmask = a_mask(optarg);
118                         set_mask = 1;
119                         break;
120                 case 'M':
121                         args.dmask = a_mask(optarg);
122                         set_dirmask = 1;
123                         break;
124                 case 'o':
125                         getmntopts(optarg, mopts, &mntflags, &opts);
126                         break;
127                 case 'r':
128                         opts |= ISOFSMNT_NORRIP;
129                         break;
130                 case 's':
131                         args.ssector = atoi(optarg);
132                         break;
133                 case 'U':
134                         opts |= ISOFSMNT_UID;
135                         args.uid = a_uid(optarg);
136                         break;
137                 case 'v':
138                         verbose++;
139                         break;
140                 case '?':
141                 default:
142                         usage();
143                 }
144         argc -= optind;
145         argv += optind;
146
147         if (argc != 2)
148                 usage();
149
150         if (set_mask && !set_dirmask) {
151                 args.dmask = args.fmask;
152                 set_dirmask = 1;
153         } else if (set_dirmask && !set_mask) {
154                 args.fmask = args.dmask;
155                 set_mask = 1;
156         }
157
158         dev = argv[0];
159         dir = argv[1];
160
161         /*
162          * Resolve the mountpoint with realpath(3) and remove unnecessary
163          * slashes from the devicename if there are any.
164          */
165         checkpath(dir, mntpath);
166         rmslashes(dev, dev);
167
168 #define DEFAULT_ROOTUID -2
169         /*
170          * ISO 9660 filesystems are not writeable.
171          */
172         mntflags |= MNT_RDONLY;
173         args.export.ex_flags = MNT_EXRDONLY;
174         args.fspec = dev;
175         args.export.ex_root = DEFAULT_ROOTUID;
176         args.flags = opts;
177
178         if (args.ssector == -1) {
179                 /*
180                  * The start of the session has not been specified on
181                  * the command line.  If we can successfully read the
182                  * TOC of a CD-ROM, use the last data track we find.
183                  * Otherwise, just use 0, in order to mount the very
184                  * first session.  This is compatible with the
185                  * historic behaviour of mount_cd9660(8).  If the user
186                  * has specified -s <ssector> above, we don't get here
187                  * and leave the user's will.
188                  */
189                 if ((args.ssector = get_ssector(dev)) == -1) {
190                         if (verbose)
191                                 printf("could not determine starting sector, "
192                                        "using very first session\n");
193                         args.ssector = 0;
194                 } else if (verbose)
195                         printf("using starting sector %d\n", args.ssector);
196         }
197
198         if (!set_mask) {
199                 if (stat(mntpath, &sb) == -1)
200                         err(EX_OSERR, "stat %s", mntpath);
201                 args.fmask = args.dmask =
202                         sb.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO);
203         }
204
205         error = getvfsbyname("cd9660", &vfc);
206         if (error && vfsisloadable("cd9660")) {
207                 if (vfsload("cd9660"))
208                         err(EX_OSERR, "vfsload(cd9660)");
209                 endvfsent();    /* flush cache */
210                 error = getvfsbyname("cd9660", &vfc);
211         }
212         if (error)
213                 errx(1, "cd9660 filesystem is not available");
214
215         if (mount(vfc.vfc_name, mntpath, mntflags, &args) < 0)
216                 err(1, "%s", args.fspec);
217         exit(0);
218 }
219
220 static int
221 set_charset(struct iso_args *args, const char *cs_local)
222 {
223         if (modfind("cd9660_iconv") < 0) {
224                 if (kldload("cd9660_iconv") < 0 ||
225                     modfind("cd9660_iconv") < 0) {
226                         warnx("cannot find or load \"cd9660_iconv\" "
227                               "kernel module");
228                         return (-1);
229                 }
230         }
231
232         snprintf(args->cs_disk, sizeof(args->cs_disk), "%s", ENCODING_UNICODE);
233         snprintf(args->cs_local, sizeof(args->cs_local), "%s", cs_local);
234         if (kiconv_add_xlat16_cspairs(args->cs_disk, args->cs_local) != 0)
235                 return (-1);
236
237         return (0);
238 }
239
240 static void
241 usage(void)
242 {
243         fprintf(stderr,
244             "usage: mount_cd9660 [-begjrv] [-C charset] [-G gid] [-m mask]\n"
245             "                    [-M mask] [-o options] [-s startsector]\n"
246             "                    [-U uid] special_node\n");
247         exit(EX_USAGE);
248 }
249
250 static int
251 get_ssector(const char *dev)
252 {
253         struct ioc_toc_header h;
254         struct ioc_read_toc_entry t;
255         struct cd_toc_entry toc_buffer[100];
256         int fd, ntocentries, i;
257
258         if ((fd = open(dev, O_RDONLY)) == -1)
259                 return -1;
260         if (ioctl(fd, CDIOREADTOCHEADER, &h) == -1) {
261                 close(fd);
262                 return -1;
263         }
264
265         ntocentries = h.ending_track - h.starting_track + 1;
266         if (ntocentries > 100) {
267                 /* unreasonable, only 100 allowed */
268                 close(fd);
269                 return -1;
270         }
271         t.address_format = CD_LBA_FORMAT;
272         t.starting_track = 0;
273         t.data_len = ntocentries * sizeof(struct cd_toc_entry);
274         t.data = toc_buffer;
275
276         if (ioctl(fd, CDIOREADTOCENTRYS, (char *) &t) == -1) {
277                 close(fd);
278                 return -1;
279         }
280         close(fd);
281
282         for (i = ntocentries - 1; i >= 0; i--)
283                 if ((toc_buffer[i].control & 4) != 0)
284                         /* found a data track */
285                         break;
286         if (i < 0)
287                 return -1;
288
289         return ntohl(toc_buffer[i].addr.lba);
290 }
291
292 static gid_t
293 a_gid(const char *s)
294 {
295         struct group *gr;
296         const char *gname;
297         gid_t gid;
298
299         if ((gr = getgrnam(s)) != NULL) {
300                 gid = gr->gr_gid;
301         } else {
302                 for (gname = s; *s && isdigit(*s); ++s)
303                         ;
304                 if (!*s)
305                         gid = atoi(gname);
306                 else
307                         errx(EX_NOUSER, "unknown group id: %s", gname);
308         }
309         return (gid);
310 }
311
312 static uid_t
313 a_uid(const char *s)
314 {
315         struct passwd *pw;
316         const char *uname;
317         uid_t uid;
318
319         if ((pw = getpwnam(s)) != NULL) {
320                 uid = pw->pw_uid;
321         } else {
322                 for (uname = s; *s && isdigit(*s); ++s)
323                         ;
324                 if (!*s)
325                         uid = atoi(uname);
326                 else
327                         errx(EX_NOUSER, "unknown user id: %s", uname);
328         }
329         return (uid);
330 }
331
332 static mode_t
333 a_mask(const char *s)
334 {
335         int done, rv;
336         char *ep;
337
338         done = 0;
339         rv = -1;
340         if (*s >= '0' && *s <= '7') {
341                 done = 1;
342                 rv = strtol(optarg, &ep, 8);
343         }
344         if (!done || rv < 0 || *ep)
345                 errx(EX_USAGE, "invalid file mode: %s", s);
346         return (rv);
347 }