]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/fetch/file.c
unfinished sblive driver, playback/mixer only for now - not enabled in
[FreeBSD/FreeBSD.git] / usr.bin / fetch / file.c
1 /*-
2  * Copyright 1997 Massachusetts Institute of Technology
3  *
4  * Permission to use, copy, modify, and distribute this software and
5  * its documentation for any purpose and without fee is hereby
6  * granted, provided that both the above copyright notice and this
7  * permission notice appear in all copies, that both the above
8  * copyright notice and this permission notice appear in all
9  * supporting documentation, and that the name of M.I.T. not be used
10  * in advertising or publicity pertaining to distribution of the
11  * software without specific, written prior permission.  M.I.T. makes
12  * no representations about the suitability of this software for any
13  * purpose.  It is provided "as is" without express or implied
14  * warranty.
15  * 
16  * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''.  M.I.T. DISCLAIMS
17  * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
18  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
20  * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
26  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * $FreeBSD$
30  */
31
32 #include <sys/types.h>
33
34 #include <err.h>
35 #include <errno.h>
36 #include <signal.h>
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <sysexits.h>
41 #include <unistd.h>
42
43 #include <sys/stat.h>
44 #include <sys/wait.h>
45
46 #include "fetch.h"
47
48 static int file_retrieve(struct fetch_state *fs);
49 static int file_close(struct fetch_state *fs);
50 static int file_parse(struct fetch_state *fs, const char *uri);
51
52 struct uri_scheme file_scheme =
53         { "file", file_parse, 0, 0, 0 };
54
55 /*
56  * Again, we slightly misinterpret the slash after the hostname as
57  * being the start of the pathname rather than merely a separator.
58  */
59 static int
60 file_parse(struct fetch_state *fs, const char *uri)
61 {
62         const char *p;
63
64         p = uri + 5;            /* skip past `file:' */
65         if (p[0] == '/' && p[1] == '/') {
66                 /* skip past `//localhost', if any */
67                 p += 2;
68                 while (*p && *p != '/')
69                         p++;
70         }
71
72         if (p[0] != '/') {
73                 warnx("`%s': expected absolute pathname in `file' URL", uri);
74                 return EX_USAGE;
75         }
76
77         fs->fs_proto = percent_decode(p);
78         /* guaranteed to succeed because of above test */
79         p = strrchr(fs->fs_proto, '/');
80         if (fs->fs_outputfile == 0) /* only set if not overridden by user */
81                 fs->fs_outputfile = p + 1;
82         fs->fs_retrieve = file_retrieve;
83         fs->fs_close = file_close;
84         return 0;
85 }
86
87 static int
88 file_close(struct fetch_state *fs)
89 {
90         free(fs->fs_proto);
91         fs->fs_proto = 0;
92         fs->fs_outputfile = 0;
93         fs->fs_status = "free";
94         return 0;
95 }
96
97 static int
98 file_retrieve(struct fetch_state *fs)
99 {
100         struct stat sb;
101
102         /* XXX - this seems bogus to me! */
103         if (access(fs->fs_outputfile, F_OK) == 0) {
104                 errno = EEXIST;
105                 warn("%s", fs->fs_outputfile);
106                 return EX_USAGE;
107         }
108
109         if (fs->fs_linkfile) {
110                 fs->fs_status = "checking path";
111                 if (stat(fs->fs_proto, &sb) == -1) {
112                         warn("%s", (char *)fs->fs_proto);
113                         return EX_NOINPUT;
114                 }
115                 fs->fs_status = "symlink";
116                 if (symlink(fs->fs_proto, fs->fs_outputfile) == -1) {
117                         warn("symlink");
118                         return EX_OSERR;
119                 }
120                 fs->fs_status = "done";
121         } else if (strcmp(fs->fs_outputfile, "-") == 0) {
122                 FILE *f;
123                 int ch;
124                 
125                 if ((f = fopen(fs->fs_proto, "r")) == NULL) {
126                         warn("fopen");
127                         return EX_OSERR;
128                 }
129                 while ((ch = fgetc(f)) != EOF)
130                         fputc(ch, stdout);
131                 if (ferror(f)) {
132                         warn("fgetc");
133                         fclose(f);
134                         return EX_OSERR;
135                 }
136                 fclose(f);
137         } else {
138                 pid_t pid;
139                 int status;
140
141                 fflush(stderr);
142                 pid = fork();
143                 if (pid < 0) {
144                         warn("fork");
145                         return EX_TEMPFAIL;
146                 } else if (pid == 0) {
147                         execl(PATH_CP, "cp", "-p", fs->fs_proto, 
148                               fs->fs_outputfile, (char *)0);
149                         warn("execl: " PATH_CP);
150                         fflush(stderr);
151                         _exit(EX_OSERR);
152                 } else {
153                         fs->fs_status = "copying";
154                         if (waitpid(pid, &status, 0) < 0) {
155                                 warn("waitpid(%ld)", (long)pid);
156                                 return EX_OSERR;
157                         }
158                         if (WIFEXITED(status))
159                                 return WEXITSTATUS(status);
160                         if (WIFSIGNALED(status))
161                                 warn(PATH_CP " exited on signal: %s",
162                                      sys_signame[WTERMSIG(status)]);
163                         return EX_OSERR;
164                 }
165         }
166         return 0;
167 }
168